package com.cdtye.shuoh.service.rule.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cdtye.shuoh.domain.enums.FieldTypeEnum;
import com.cdtye.shuoh.domain.enums.OperatorEnum;
import com.cdtye.shuoh.domain.enums.TriggeringEnum;
import com.cdtye.shuoh.domain.product.entity.ProductProperties;
import com.cdtye.shuoh.domain.rule.entity.Rule;
import com.cdtye.shuoh.domain.rule.entity.RuleAlarmList;
import com.cdtye.shuoh.domain.rule.entity.RuleConditions;
import com.cdtye.shuoh.domain.rule.vo.RuleConditionsVo;
import com.cdtye.shuoh.domain.rule.vo.RuleVo;
import com.cdtye.shuoh.mapper.rule.RuleMapper;
import com.cdtye.shuoh.service.product.ProductPropertiesService;
import com.cdtye.shuoh.service.rule.RuleAlarmListService;
import com.cdtye.shuoh.service.rule.RuleConditionsService;
import com.cdtye.shuoh.service.rule.RuleService;
import com.cdtye.shuoh.util.text.CompareUtil;
import com.cdtye.shuoh.util.text.UUID;
import com.google.common.base.CaseFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class RuleServiceImpl extends ServiceImpl<RuleMapper, Rule> implements RuleService {

    @Autowired
    private RuleMapper ruleMapper;

    @Autowired
    private RuleConditionsService ruleConditionsService;

    @Autowired
    private ProductPropertiesService productPropertiesService;

    @Autowired
    private RuleAlarmListService ruleAlarmListService;

    @Override
    public IPage<Rule> pageList(RuleVo vo) {
        return ruleMapper.pageList(vo.page(),vo);
    }

    @Override
    public List<Rule> list(RuleVo vo) {
        List<Rule> result = ruleMapper.list(vo);
        result.forEach(rule->{
            RuleConditionsVo conditionsVo = new RuleConditionsVo();
            conditionsVo.setRuleIdentification(rule.getRuleIdentification());
            rule.setConditionsList(ruleConditionsService.list(conditionsVo));
        });
        return result;
    }

    @Override
    public Boolean insertRule(Rule rule) {
        rule.setRuleType("0");
        rule.setRuleIdentification(UUID.getUUID());
        boolean flag = this.save(rule);
        if(flag){
            List<RuleConditions> conditionsList = rule.getConditionsList();
            conditionsList.forEach(c->{c.setRuleIdentification(rule.getRuleIdentification());});
            flag = ruleConditionsService.saveBatch(conditionsList);
        }
        return flag;
    }

    @Override
    public Boolean updateRule(Rule rule) {
        boolean flag = this.updateById(rule);
        if(flag){
            List<RuleConditions> conditionsList = rule.getConditionsList();
            conditionsList.forEach(c->{c.setRuleIdentification(rule.getRuleIdentification());});
            flag = ruleConditionsService.updateBatchById(conditionsList);
        }
        return flag;
    }

    @Override
    public Rule getRuleById(String id) {
       Rule rule = getById(id);
       RuleConditionsVo conditionsVo = new RuleConditionsVo();
       conditionsVo.setRuleIdentification(rule.getRuleIdentification());
       rule.setConditionsList(ruleConditionsService.list(conditionsVo));
       return rule;
    }

    @Override
    public void processingRule(String productIdentification, String serviceId,String deviceIdentification,Date time, Map<String, Object> data){
        RuleVo vo = new RuleVo();
        vo.setProductIdentification(productIdentification);
        vo.setServiceId(serviceId);
        vo.setState("1");
        List<Rule> ruleList = list(vo);
        // 存放比较结果
        List<Boolean> flags = new ArrayList<>();
        for (Rule rule : ruleList) {
            for (RuleConditions ruleConditions : rule.getConditionsList()) {
                ProductProperties productProperties = productPropertiesService.getById(ruleConditions.getPropertiesId());
                if (null == productProperties){
                    continue;
                }
                // 属性名称
                String productPropertiesName = productProperties.getName();
                // 属性类型
                String productPropertiesType = productProperties.getDatatype();
                // 比较模式
                String comparisonMode = ruleConditions.getComparisonMode();
                // 比较值
                String comparisonValue = ruleConditions.getComparisonValue();
                if (data.containsKey(productPropertiesName) || data.containsKey(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, productPropertiesName))) {
                    // 获取属性实际的值
                    String realValue = data.containsKey(productPropertiesName) ? data.get(productPropertiesName).toString() : (data.containsValue(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, productPropertiesName)) ? data.get(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, productPropertiesName)).toString() : null);
                    flags.add(compare(comparisonMode, productPropertiesType, realValue, comparisonValue));
                }
            }
            boolean mark = false;
            if (null == flags || flags.isEmpty()) {
                // 验证条件
                return;
            }
            switch (TriggeringEnum.getBySymbol(Integer.valueOf(rule.getTriggering()))) {
                case ALL:
                    mark = flags.stream().allMatch(s -> s.equals(true));
                    break;
                case ANY:
                    mark = flags.stream().anyMatch(s -> s.equals(true));
                    break;
                default:
                    break;
            }
            if(mark){
                RuleAlarmList alarm = new RuleAlarmList();
                alarm.setAlarmData(data.toString());
                alarm.setAlarmName(rule.getRuleName());
                alarm.setDeviceIdentification(deviceIdentification);
                alarm.setRuleIdentification(rule.getRuleIdentification());
                alarm.setAlarmTime(time);
                ruleAlarmListService.insertAlarmInfo(alarm);
            }
        }
    }

    @Override
    public boolean deleteRuleById(String id) {
        if(null == id) return true;
        Rule rule = getById(id);
        boolean flag = ruleConditionsService.deleteByRuleIdentification(rule.getRuleIdentification());
        if(flag){
            return this.removeById(id);
        }
        return false;
    }

    /**
     * 实现计算
     *
     * @param symbol          运算符
     * @param propertiesType  属性类型
     * @param actualValue     实际值
     * @param comparisonValue 比较值
     * @return
     */
    private boolean compare(String symbol, String propertiesType, String actualValue, String comparisonValue) {
        boolean flag = false;
        FieldTypeEnum bySymbol = FieldTypeEnum.getBySymbol(propertiesType);
        // 判断比较类型
        switch (OperatorEnum.getBySymbol(symbol)) {
            case eq:
                // 判断属性值类型
                switch (bySymbol) {
                    case INT:
                        flag = Integer.parseInt(actualValue) == Integer.parseInt(comparisonValue);
                        break;
                    case STRING:
                        flag = actualValue.equals(comparisonValue);
                        break;
                    case FLOAT:
                        flag = Double.parseDouble(actualValue) == Double.parseDouble(comparisonValue);
                        break;
                    case TIMESTAMP:
                        break;
                    case BOOL:
                        break;
                    default:
                        break;
                }
                break;
            case not:
                // 判断属性值类型
                switch (bySymbol) {
                    case INT:
                        flag = Integer.parseInt(actualValue) != Integer.parseInt(comparisonValue);
                        break;
                    case STRING:
                        flag = !actualValue.equals(comparisonValue);
                        break;
                    case FLOAT:
                        flag = Double.parseDouble(actualValue) != Double.parseDouble(comparisonValue);
                        break;
                    case TIMESTAMP:
                        break;
                    case BOOL:
                        break;
                    default:
                        break;
                }
                break;
            case gt:
                // 判断属性值类型
                switch (bySymbol) {
                    case INT:
                        flag = Integer.parseInt(actualValue) > Integer.parseInt(comparisonValue);
                        break;
                    case FLOAT:
                        flag = Double.parseDouble(actualValue) > Double.parseDouble(comparisonValue);
                        break;
                    case TIMESTAMP:
                        break;
                    case BOOL:
                        break;
                    default:
                        break;
                }
                break;
            case lt:
                // 判断属性值类型
                switch (bySymbol) {
                    case INT:
                        flag = Integer.parseInt(actualValue) < Integer.parseInt(comparisonValue);
                        break;
                    case FLOAT:
                        flag = Double.parseDouble(actualValue) < Double.parseDouble(comparisonValue);
                        break;
                    case TIMESTAMP:
                        break;
                    case BOOL:
                        break;
                    default:
                        break;
                }
                break;
            case gte:
                // 判断属性值类型
                switch (bySymbol) {
                    case INT:
                        flag = Integer.parseInt(actualValue) >= Integer.parseInt(comparisonValue);
                        break;
                    case FLOAT:
                        flag = Double.parseDouble(actualValue) >= Double.parseDouble(comparisonValue);
                        break;
                    case TIMESTAMP:
                        break;
                    case BOOL:
                        break;
                    default:
                        break;
                }
                break;
            case lte:
                // 判断属性值类型
                switch (bySymbol) {
                    case INT:
                        flag = Integer.parseInt(actualValue) <= Integer.parseInt(comparisonValue);
                        break;
                    case FLOAT:
                        flag = Double.parseDouble(actualValue) <= Double.parseDouble(comparisonValue);
                        break;
                    case TIMESTAMP:
                        break;
                    case BOOL:
                        break;
                    default:
                        break;
                }
                break;
            case between:
                // 判断属性值类型
                switch (bySymbol) {
                    case INT:
                        int[] arrayint = Arrays.asList(comparisonValue.split(",")).stream().mapToInt(Integer::parseInt).toArray();
                        flag = CompareUtil.rangeInDefinedInt(Integer.parseInt(actualValue), arrayint[0], arrayint[1]);
                        break;
                    case FLOAT:
                        double[] arrayDouble = Arrays.asList(comparisonValue.split(",")).stream().mapToDouble(Double::parseDouble).toArray();
                        flag = CompareUtil.rangeInDefinedDouble(Double.parseDouble(actualValue), arrayDouble[0], arrayDouble[1]);
                        break;
                    case TIMESTAMP:
                        break;
                    case BOOL:
                        break;
                    default:
                        break;
                }
                break;
            default:
                break;
        }
        return flag;
    }
}
